1   /*                        __    __  __  __    __  ___
2    *                       \  \  /  /    \  \  /  /  __/
3    *                        \  \/  /  /\  \  \/  /  /
4    *                         \____/__/  \__\____/__/.ɪᴏ
5    * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
6    */
7   package io.vavr.collection;
8   
9   import io.vavr.*;
10  import io.vavr.control.Option;
11  
12  import java.io.*;
13  import java.util.ArrayList;
14  import java.util.Comparator;
15  import java.util.NoSuchElementException;
16  import java.util.Objects;
17  import java.util.function.*;
18  import java.util.stream.Collector;
19  
20  /**
21   * An immutable {@code HashSet} implementation.
22   *
23   * @param <T> Component type
24   * @author Ruslan Sennov, Patryk Najda, Daniel Dietrich
25   */
26  public final class HashSet<T> implements Set<T>, Serializable {
27  
28      private static final long serialVersionUID = 1L;
29  
30      private static final HashSet<?> EMPTY = new HashSet<>(HashArrayMappedTrie.empty());
31  
32      private final HashArrayMappedTrie<T, T> tree;
33  
34      private HashSet(HashArrayMappedTrie<T, T> tree) {
35          this.tree = tree;
36      }
37  
38      @SuppressWarnings("unchecked")
39      public static <T> HashSet<T> empty() {
40          return (HashSet<T>) EMPTY;
41      }
42  
43      /**
44       * Returns a {@link java.util.stream.Collector} which may be used in conjunction with
45       * {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link HashSet}.
46       *
47       * @param <T> Component type of the HashSet.
48       * @return A io.vavr.collection.HashSet Collector.
49       */
50      public static <T> Collector<T, ArrayList<T>, HashSet<T>> collector() {
51          final Supplier<ArrayList<T>> supplier = ArrayList::new;
52          final BiConsumer<ArrayList<T>, T> accumulator = ArrayList::add;
53          final BinaryOperator<ArrayList<T>> combiner = (left, right) -> {
54              left.addAll(right);
55              return left;
56          };
57          final Function<ArrayList<T>, HashSet<T>> finisher = HashSet::ofAll;
58          return Collector.of(supplier, accumulator, combiner, finisher);
59      }
60  
61      /**
62       * Narrows a widened {@code HashSet<? extends T>} to {@code HashSet<T>}
63       * by performing a type-safe cast. This is eligible because immutable/read-only
64       * collections are covariant.
65       *
66       * @param hashSet A {@code HashSet}.
67       * @param <T>     Component type of the {@code HashSet}.
68       * @return the given {@code hashSet} instance as narrowed type {@code HashSet<T>}.
69       */
70      @SuppressWarnings("unchecked")
71      public static <T> HashSet<T> narrow(HashSet<? extends T> hashSet) {
72          return (HashSet<T>) hashSet;
73      }
74  
75      /**
76       * Returns a singleton {@code HashSet}, i.e. a {@code HashSet} of one element.
77       *
78       * @param element An element.
79       * @param <T>     The component type
80       * @return A new HashSet instance containing the given element
81       */
82      public static <T> HashSet<T> of(T element) {
83          return HashSet.<T> empty().add(element);
84      }
85  
86      /**
87       * Creates a HashSet of the given elements.
88       *
89       * <pre><code>HashSet.of(1, 2, 3, 4)</code></pre>
90       *
91       * @param <T>      Component type of the HashSet.
92       * @param elements Zero or more elements.
93       * @return A set containing the given elements.
94       * @throws NullPointerException if {@code elements} is null
95       */
96      @SafeVarargs
97      public static <T> HashSet<T> of(T... elements) {
98          Objects.requireNonNull(elements, "elements is null");
99          HashArrayMappedTrie<T, T> tree = HashArrayMappedTrie.empty();
100         for (T element : elements) {
101             tree = tree.put(element, element);
102         }
103         return tree.isEmpty() ? empty() : new HashSet<>(tree);
104     }
105 
106     /**
107      * Returns an HashSet containing {@code n} values of a given Function {@code f}
108      * over a range of integer values from 0 to {@code n - 1}.
109      *
110      * @param <T> Component type of the HashSet
111      * @param n   The number of elements in the HashSet
112      * @param f   The Function computing element values
113      * @return An HashSet consisting of elements {@code f(0),f(1), ..., f(n - 1)}
114      * @throws NullPointerException if {@code f} is null
115      */
116     public static <T> HashSet<T> tabulate(int n, Function<? super Integer, ? extends T> f) {
117         Objects.requireNonNull(f, "f is null");
118         return Collections.tabulate(n, f, HashSet.empty(), HashSet::of);
119     }
120 
121     /**
122      * Returns an HashSet containing {@code n} values supplied by a given Supplier {@code s}.
123      *
124      * @param <T> Component type of the HashSet
125      * @param n   The number of elements in the HashSet
126      * @param s   The Supplier computing element values
127      * @return An HashSet of size {@code n}, where each element contains the result supplied by {@code s}.
128      * @throws NullPointerException if {@code s} is null
129      */
130     public static <T> HashSet<T> fill(int n, Supplier<? extends T> s) {
131         Objects.requireNonNull(s, "s is null");
132         return Collections.fill(n, s, HashSet.empty(), HashSet::of);
133     }
134 
135     /**
136      * Creates a HashSet of the given elements.
137      *
138      * @param elements Set elements
139      * @param <T>      The value type
140      * @return A new HashSet containing the given entries
141      */
142     @SuppressWarnings("unchecked")
143     public static <T> HashSet<T> ofAll(Iterable<? extends T> elements) {
144         Objects.requireNonNull(elements, "elements is null");
145         if (elements instanceof HashSet) {
146             return (HashSet<T>) elements;
147         } else {
148             final HashArrayMappedTrie<T, T> tree = addAll(HashArrayMappedTrie.empty(), elements);
149             return tree.isEmpty() ? empty() : new HashSet<>(tree);
150         }
151     }
152 
153     /**
154      * Creates a HashSet that contains the elements of the given {@link java.util.stream.Stream}.
155      *
156      * @param javaStream A {@link java.util.stream.Stream}
157      * @param <T>        Component type of the Stream.
158      * @return A HashSet containing the given elements in the same order.
159      */
160     public static <T> HashSet<T> ofAll(java.util.stream.Stream<? extends T> javaStream) {
161         Objects.requireNonNull(javaStream, "javaStream is null");
162         return HashSet.ofAll(Iterator.ofAll(javaStream.iterator()));
163     }
164 
165     /**
166      * Creates a HashSet from boolean values.
167      *
168      * @param elements boolean values
169      * @return A new HashSet of Boolean values
170      * @throws NullPointerException if elements is null
171      */
172     public static HashSet<Boolean> ofAll(boolean... elements) {
173         Objects.requireNonNull(elements, "elements is null");
174         return HashSet.ofAll(Iterator.ofAll(elements));
175     }
176 
177     /**
178      * Creates a HashSet from byte values.
179      *
180      * @param elements byte values
181      * @return A new HashSet of Byte values
182      * @throws NullPointerException if elements is null
183      */
184     public static HashSet<Byte> ofAll(byte... elements) {
185         Objects.requireNonNull(elements, "elements is null");
186         return HashSet.ofAll(Iterator.ofAll(elements));
187     }
188 
189     /**
190      * Creates a HashSet from char values.
191      *
192      * @param elements char values
193      * @return A new HashSet of Character values
194      * @throws NullPointerException if elements is null
195      */
196     public static HashSet<Character> ofAll(char... elements) {
197         Objects.requireNonNull(elements, "elements is null");
198         return HashSet.ofAll(Iterator.ofAll(elements));
199     }
200 
201     /**
202      * Creates a HashSet from double values.
203      *
204      * @param elements double values
205      * @return A new HashSet of Double values
206      * @throws NullPointerException if elements is null
207      */
208     public static HashSet<Double> ofAll(double... elements) {
209         Objects.requireNonNull(elements, "elements is null");
210         return HashSet.ofAll(Iterator.ofAll(elements));
211     }
212 
213     /**
214      * Creates a HashSet from float values.
215      *
216      * @param elements float values
217      * @return A new HashSet of Float values
218      * @throws NullPointerException if elements is null
219      */
220     public static HashSet<Float> ofAll(float... elements) {
221         Objects.requireNonNull(elements, "elements is null");
222         return HashSet.ofAll(Iterator.ofAll(elements));
223     }
224 
225     /**
226      * Creates a HashSet from int values.
227      *
228      * @param elements int values
229      * @return A new HashSet of Integer values
230      * @throws NullPointerException if elements is null
231      */
232     public static HashSet<Integer> ofAll(int... elements) {
233         Objects.requireNonNull(elements, "elements is null");
234         return HashSet.ofAll(Iterator.ofAll(elements));
235     }
236 
237     /**
238      * Creates a HashSet from long values.
239      *
240      * @param elements long values
241      * @return A new HashSet of Long values
242      * @throws NullPointerException if elements is null
243      */
244     public static HashSet<Long> ofAll(long... elements) {
245         Objects.requireNonNull(elements, "elements is null");
246         return HashSet.ofAll(Iterator.ofAll(elements));
247     }
248 
249     /**
250      * Creates a HashSet from short values.
251      *
252      * @param elements short values
253      * @return A new HashSet of Short values
254      * @throws NullPointerException if elements is null
255      */
256     public static HashSet<Short> ofAll(short... elements) {
257         Objects.requireNonNull(elements, "elements is null");
258         return HashSet.ofAll(Iterator.ofAll(elements));
259     }
260 
261     /**
262      * Creates a HashSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1}.
263      * <p>
264      * Examples:
265      * <pre>
266      * <code>
267      * HashSet.range(0, 0)  // = HashSet()
268      * HashSet.range(2, 0)  // = HashSet()
269      * HashSet.range(-2, 2) // = HashSet(-2, -1, 0, 1)
270      * </code>
271      * </pre>
272      *
273      * @param from        the first number
274      * @param toExclusive the last number + 1
275      * @return a range of int values as specified or the empty range if {@code from >= toExclusive}
276      */
277     public static HashSet<Integer> range(int from, int toExclusive) {
278         return HashSet.ofAll(Iterator.range(from, toExclusive));
279     }
280 
281     public static HashSet<Character> range(char from, char toExclusive) {
282         return HashSet.ofAll(Iterator.range(from, toExclusive));
283     }
284 
285     /**
286      * Creates a HashSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1},
287      * with {@code step}.
288      * <p>
289      * Examples:
290      * <pre>
291      * <code>
292      * HashSet.rangeBy(1, 3, 1)  // = HashSet(1, 2)
293      * HashSet.rangeBy(1, 4, 2)  // = HashSet(1, 3)
294      * HashSet.rangeBy(4, 1, -2) // = HashSet(4, 2)
295      * HashSet.rangeBy(4, 1, 2)  // = HashSet()
296      * </code>
297      * </pre>
298      *
299      * @param from        the first number
300      * @param toExclusive the last number + 1
301      * @param step        the step
302      * @return a range of long values as specified or the empty range if<br>
303      * {@code from >= toInclusive} and {@code step > 0} or<br>
304      * {@code from <= toInclusive} and {@code step < 0}
305      * @throws IllegalArgumentException if {@code step} is zero
306      */
307     public static HashSet<Integer> rangeBy(int from, int toExclusive, int step) {
308         return HashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
309     }
310 
311     public static HashSet<Character> rangeBy(char from, char toExclusive, int step) {
312         return HashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
313     }
314 
315     @GwtIncompatible
316     public static HashSet<Double> rangeBy(double from, double toExclusive, double step) {
317         return HashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
318     }
319 
320     /**
321      * Creates a HashSet of long numbers starting from {@code from}, extending to {@code toExclusive - 1}.
322      * <p>
323      * Examples:
324      * <pre>
325      * <code>
326      * HashSet.range(0L, 0L)  // = HashSet()
327      * HashSet.range(2L, 0L)  // = HashSet()
328      * HashSet.range(-2L, 2L) // = HashSet(-2L, -1L, 0L, 1L)
329      * </code>
330      * </pre>
331      *
332      * @param from        the first number
333      * @param toExclusive the last number + 1
334      * @return a range of long values as specified or the empty range if {@code from >= toExclusive}
335      */
336     public static HashSet<Long> range(long from, long toExclusive) {
337         return HashSet.ofAll(Iterator.range(from, toExclusive));
338     }
339 
340     /**
341      * Creates a HashSet of long numbers starting from {@code from}, extending to {@code toExclusive - 1},
342      * with {@code step}.
343      * <p>
344      * Examples:
345      * <pre>
346      * <code>
347      * HashSet.rangeBy(1L, 3L, 1L)  // = HashSet(1L, 2L)
348      * HashSet.rangeBy(1L, 4L, 2L)  // = HashSet(1L, 3L)
349      * HashSet.rangeBy(4L, 1L, -2L) // = HashSet(4L, 2L)
350      * HashSet.rangeBy(4L, 1L, 2L)  // = HashSet()
351      * </code>
352      * </pre>
353      *
354      * @param from        the first number
355      * @param toExclusive the last number + 1
356      * @param step        the step
357      * @return a range of long values as specified or the empty range if<br>
358      * {@code from >= toInclusive} and {@code step > 0} or<br>
359      * {@code from <= toInclusive} and {@code step < 0}
360      * @throws IllegalArgumentException if {@code step} is zero
361      */
362     public static HashSet<Long> rangeBy(long from, long toExclusive, long step) {
363         return HashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
364     }
365 
366     /**
367      * Creates a HashSet of int numbers starting from {@code from}, extending to {@code toInclusive}.
368      * <p>
369      * Examples:
370      * <pre>
371      * <code>
372      * HashSet.rangeClosed(0, 0)  // = HashSet(0)
373      * HashSet.rangeClosed(2, 0)  // = HashSet()
374      * HashSet.rangeClosed(-2, 2) // = HashSet(-2, -1, 0, 1, 2)
375      * </code>
376      * </pre>
377      *
378      * @param from        the first number
379      * @param toInclusive the last number
380      * @return a range of int values as specified or the empty range if {@code from > toInclusive}
381      */
382     public static HashSet<Integer> rangeClosed(int from, int toInclusive) {
383         return HashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
384     }
385 
386     public static HashSet<Character> rangeClosed(char from, char toInclusive) {
387         return HashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
388     }
389 
390     /**
391      * Creates a HashSet of int numbers starting from {@code from}, extending to {@code toInclusive},
392      * with {@code step}.
393      * <p>
394      * Examples:
395      * <pre>
396      * <code>
397      * HashSet.rangeClosedBy(1, 3, 1)  // = HashSet(1, 2, 3)
398      * HashSet.rangeClosedBy(1, 4, 2)  // = HashSet(1, 3)
399      * HashSet.rangeClosedBy(4, 1, -2) // = HashSet(4, 2)
400      * HashSet.rangeClosedBy(4, 1, 2)  // = HashSet()
401      * </code>
402      * </pre>
403      *
404      * @param from        the first number
405      * @param toInclusive the last number
406      * @param step        the step
407      * @return a range of int values as specified or the empty range if<br>
408      * {@code from > toInclusive} and {@code step > 0} or<br>
409      * {@code from < toInclusive} and {@code step < 0}
410      * @throws IllegalArgumentException if {@code step} is zero
411      */
412     public static HashSet<Integer> rangeClosedBy(int from, int toInclusive, int step) {
413         return HashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
414     }
415 
416     public static HashSet<Character> rangeClosedBy(char from, char toInclusive, int step) {
417         return HashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
418     }
419 
420     @GwtIncompatible
421     public static HashSet<Double> rangeClosedBy(double from, double toInclusive, double step) {
422         return HashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
423     }
424 
425     /**
426      * Creates a HashSet of long numbers starting from {@code from}, extending to {@code toInclusive}.
427      * <p>
428      * Examples:
429      * <pre>
430      * <code>
431      * HashSet.rangeClosed(0L, 0L)  // = HashSet(0L)
432      * HashSet.rangeClosed(2L, 0L)  // = HashSet()
433      * HashSet.rangeClosed(-2L, 2L) // = HashSet(-2L, -1L, 0L, 1L, 2L)
434      * </code>
435      * </pre>
436      *
437      * @param from        the first number
438      * @param toInclusive the last number
439      * @return a range of long values as specified or the empty range if {@code from > toInclusive}
440      */
441     public static HashSet<Long> rangeClosed(long from, long toInclusive) {
442         return HashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
443     }
444 
445     /**
446      * Creates a HashSet of long numbers starting from {@code from}, extending to {@code toInclusive},
447      * with {@code step}.
448      * <p>
449      * Examples:
450      * <pre>
451      * <code>
452      * HashSet.rangeClosedBy(1L, 3L, 1L)  // = HashSet(1L, 2L, 3L)
453      * HashSet.rangeClosedBy(1L, 4L, 2L)  // = HashSet(1L, 3L)
454      * HashSet.rangeClosedBy(4L, 1L, -2L) // = HashSet(4L, 2L)
455      * HashSet.rangeClosedBy(4L, 1L, 2L)  // = HashSet()
456      * </code>
457      * </pre>
458      *
459      * @param from        the first number
460      * @param toInclusive the last number
461      * @param step        the step
462      * @return a range of int values as specified or the empty range if<br>
463      * {@code from > toInclusive} and {@code step > 0} or<br>
464      * {@code from < toInclusive} and {@code step < 0}
465      * @throws IllegalArgumentException if {@code step} is zero
466      */
467     public static HashSet<Long> rangeClosedBy(long from, long toInclusive, long step) {
468         return HashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
469     }
470 
471     @Override
472     public HashSet<T> add(T element) {
473         return contains(element) ? this : new HashSet<>(tree.put(element, element));
474     }
475 
476     @Override
477     public HashSet<T> addAll(Iterable<? extends T> elements) {
478         Objects.requireNonNull(elements, "elements is null");
479         if (isEmpty() && elements instanceof HashSet) {
480             @SuppressWarnings("unchecked")
481             final HashSet<T> set = (HashSet<T>) elements;
482             return set;
483         }
484         final HashArrayMappedTrie<T, T> that = addAll(tree, elements);
485         if (that.size() == tree.size()) {
486             return this;
487         } else {
488             return new HashSet<>(that);
489         }
490     }
491 
492     @Override
493     public <R> HashSet<R> collect(PartialFunction<? super T, ? extends R> partialFunction) {
494         return ofAll(iterator().<R> collect(partialFunction));
495     }
496 
497     @Override
498     public boolean contains(T element) {
499         return tree.get(element).isDefined();
500     }
501 
502     @Override
503     public HashSet<T> diff(Set<? extends T> elements) {
504         Objects.requireNonNull(elements, "elements is null");
505         if (isEmpty() || elements.isEmpty()) {
506             return this;
507         } else {
508             return removeAll(elements);
509         }
510     }
511 
512     @Override
513     public HashSet<T> distinct() {
514         return this;
515     }
516 
517     @Override
518     public HashSet<T> distinctBy(Comparator<? super T> comparator) {
519         Objects.requireNonNull(comparator, "comparator is null");
520         return HashSet.ofAll(iterator().distinctBy(comparator));
521     }
522 
523     @Override
524     public <U> HashSet<T> distinctBy(Function<? super T, ? extends U> keyExtractor) {
525         Objects.requireNonNull(keyExtractor, "keyExtractor is null");
526         return HashSet.ofAll(iterator().distinctBy(keyExtractor));
527     }
528 
529     @Override
530     public HashSet<T> drop(int n) {
531         if (n <= 0) {
532             return this;
533         } else {
534             return HashSet.ofAll(iterator().drop(n));
535         }
536     }
537 
538     @Override
539     public HashSet<T> dropRight(int n) {
540         return drop(n);
541     }
542 
543     @Override
544     public HashSet<T> dropUntil(Predicate<? super T> predicate) {
545         Objects.requireNonNull(predicate, "predicate is null");
546         return dropWhile(predicate.negate());
547     }
548 
549     @Override
550     public HashSet<T> dropWhile(Predicate<? super T> predicate) {
551         Objects.requireNonNull(predicate, "predicate is null");
552         final HashSet<T> dropped = HashSet.ofAll(iterator().dropWhile(predicate));
553         return dropped.length() == length() ? this : dropped;
554     }
555 
556     @Override
557     public HashSet<T> filter(Predicate<? super T> predicate) {
558         Objects.requireNonNull(predicate, "predicate is null");
559         final HashSet<T> filtered = HashSet.ofAll(iterator().filter(predicate));
560 
561         if (filtered.isEmpty()) {
562             return empty();
563         } else if (filtered.length() == length()) {
564             return this;
565         } else {
566             return filtered;
567         }
568     }
569 
570     @Override
571     public <U> HashSet<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper) {
572         Objects.requireNonNull(mapper, "mapper is null");
573         if (isEmpty()) {
574             return empty();
575         } else {
576             final HashArrayMappedTrie<U, U> that = foldLeft(HashArrayMappedTrie.empty(),
577                     (tree, t) -> addAll(tree, mapper.apply(t)));
578             return new HashSet<>(that);
579         }
580     }
581 
582     @Override
583     public <U> U foldRight(U zero, BiFunction<? super T, ? super U, ? extends U> f) {
584         return foldLeft(zero, (u, t) -> f.apply(t, u));
585     }
586 
587     @Override
588     public <C> Map<C, HashSet<T>> groupBy(Function<? super T, ? extends C> classifier) {
589         return Collections.groupBy(this, classifier, HashSet::ofAll);
590     }
591 
592     @Override
593     public Iterator<HashSet<T>> grouped(int size) {
594         return sliding(size, size);
595     }
596 
597     @Override
598     public boolean hasDefiniteSize() {
599         return true;
600     }
601 
602     @Override
603     public T head() {
604         if (tree.isEmpty()) {
605             throw new NoSuchElementException("head of empty set");
606         }
607         return iterator().next();
608     }
609 
610     @Override
611     public Option<T> headOption() {
612         return iterator().headOption();
613     }
614 
615     @Override
616     public HashSet<T> init() {
617         return tail();
618     }
619 
620     @Override
621     public Option<HashSet<T>> initOption() {
622         return tailOption();
623     }
624 
625     @Override
626     public HashSet<T> intersect(Set<? extends T> elements) {
627         Objects.requireNonNull(elements, "elements is null");
628         if (isEmpty() || elements.isEmpty()) {
629             return empty();
630         } else {
631             final int size = size();
632             if (size <= elements.size()) {
633                 return retainAll(elements);
634             } else {
635                 final HashSet<T> results = HashSet.<T> ofAll(elements).retainAll(this);
636                 return (size == results.size()) ? this : results;
637             }
638         }
639     }
640 
641     /**
642      * A {@code HashSet} is computed synchronously.
643      *
644      * @return false
645      */
646     @Override
647     public boolean isAsync() {
648         return false;
649     }
650 
651     @Override
652     public boolean isEmpty() {
653         return tree.isEmpty();
654     }
655     
656     /**
657      * A {@code HashSet} is computed eagerly.
658      *
659      * @return false
660      */
661     @Override
662     public boolean isLazy() {
663         return false;
664     }
665 
666     @Override
667     public boolean isTraversableAgain() {
668         return true;
669     }
670 
671     @Override
672     public Iterator<T> iterator() {
673         return tree.keysIterator();
674     }
675 
676     @Override
677     public int length() {
678         return tree.size();
679     }
680 
681     @Override
682     public <U> HashSet<U> map(Function<? super T, ? extends U> mapper) {
683         Objects.requireNonNull(mapper, "mapper is null");
684         if (isEmpty()) {
685             return empty();
686         } else {
687             final HashArrayMappedTrie<U, U> that = foldLeft(HashArrayMappedTrie.empty(), (tree, t) -> {
688                 final U u = mapper.apply(t);
689                 return tree.put(u, u);
690             });
691             return new HashSet<>(that);
692         }
693     }
694 
695     @Override
696     public String mkString(CharSequence prefix, CharSequence delimiter, CharSequence suffix) {
697         return iterator().mkString(prefix, delimiter, suffix);
698     }
699 
700     @Override
701     public HashSet<T> orElse(Iterable<? extends T> other) {
702         return isEmpty() ? ofAll(other) : this;
703     }
704 
705     @Override
706     public HashSet<T> orElse(Supplier<? extends Iterable<? extends T>> supplier) {
707         return isEmpty() ? ofAll(supplier.get()) : this;
708     }
709 
710     @Override
711     public Tuple2<HashSet<T>, HashSet<T>> partition(Predicate<? super T> predicate) {
712         Objects.requireNonNull(predicate, "predicate is null");
713         final Tuple2<Iterator<T>, Iterator<T>> p = iterator().partition(predicate);
714         return Tuple.of(HashSet.ofAll(p._1), HashSet.ofAll(p._2));
715     }
716 
717     @Override
718     public HashSet<T> peek(Consumer<? super T> action) {
719         Objects.requireNonNull(action, "action is null");
720         if (!isEmpty()) {
721             action.accept(iterator().head());
722         }
723         return this;
724     }
725 
726     @Override
727     public HashSet<T> remove(T element) {
728         final HashArrayMappedTrie<T, T> newTree = tree.remove(element);
729         return (newTree == tree) ? this : new HashSet<>(newTree);
730     }
731 
732     @Override
733     public HashSet<T> removeAll(Iterable<? extends T> elements) {
734         return Collections.removeAll(this, elements);
735     }
736 
737     @Override
738     public HashSet<T> replace(T currentElement, T newElement) {
739         if (tree.containsKey(currentElement)) {
740             return remove(currentElement).add(newElement);
741         } else {
742             return this;
743         }
744     }
745 
746     @Override
747     public HashSet<T> replaceAll(T currentElement, T newElement) {
748         return replace(currentElement, newElement);
749     }
750 
751     @Override
752     public HashSet<T> retainAll(Iterable<? extends T> elements) {
753         return Collections.retainAll(this, elements);
754     }
755 
756     @Override
757     public HashSet<T> scan(T zero, BiFunction<? super T, ? super T, ? extends T> operation) {
758         return scanLeft(zero, operation);
759     }
760 
761     @Override
762     public <U> HashSet<U> scanLeft(U zero, BiFunction<? super U, ? super T, ? extends U> operation) {
763         return Collections.scanLeft(this, zero, operation, HashSet::ofAll);
764     }
765 
766     @Override
767     public <U> HashSet<U> scanRight(U zero, BiFunction<? super T, ? super U, ? extends U> operation) {
768         return Collections.scanRight(this, zero, operation, HashSet::ofAll);
769     }
770 
771     @Override
772     public Iterator<HashSet<T>> slideBy(Function<? super T, ?> classifier) {
773         return iterator().slideBy(classifier).map(HashSet::ofAll);
774     }
775 
776     @Override
777     public Iterator<HashSet<T>> sliding(int size) {
778         return sliding(size, 1);
779     }
780 
781     @Override
782     public Iterator<HashSet<T>> sliding(int size, int step) {
783         return iterator().sliding(size, step).map(HashSet::ofAll);
784     }
785 
786     @Override
787     public Tuple2<HashSet<T>, HashSet<T>> span(Predicate<? super T> predicate) {
788         Objects.requireNonNull(predicate, "predicate is null");
789         final Tuple2<Iterator<T>, Iterator<T>> t = iterator().span(predicate);
790         return Tuple.of(HashSet.ofAll(t._1), HashSet.ofAll(t._2));
791     }
792 
793     @Override
794     public HashSet<T> tail() {
795         if (tree.isEmpty()) {
796             throw new UnsupportedOperationException("tail of empty set");
797         }
798         return remove(head());
799     }
800 
801     @Override
802     public Option<HashSet<T>> tailOption() {
803         if (tree.isEmpty()) {
804             return Option.none();
805         } else {
806             return Option.some(tail());
807         }
808     }
809 
810     @Override
811     public HashSet<T> take(int n) {
812         if (n >= size() || isEmpty()) {
813             return this;
814         } else if (n <= 0) {
815             return empty();
816         } else {
817             return ofAll(() -> iterator().take(n));
818         }
819     }
820 
821     @Override
822     public HashSet<T> takeRight(int n) {
823         return take(n);
824     }
825 
826     @Override
827     public HashSet<T> takeUntil(Predicate<? super T> predicate) {
828         Objects.requireNonNull(predicate, "predicate is null");
829         return takeWhile(predicate.negate());
830     }
831 
832     @Override
833     public HashSet<T> takeWhile(Predicate<? super T> predicate) {
834         Objects.requireNonNull(predicate, "predicate is null");
835         final HashSet<T> taken = HashSet.ofAll(iterator().takeWhile(predicate));
836         return taken.length() == length() ? this : taken;
837     }
838 
839     /**
840      * Transforms this {@code HashSet}.
841      *
842      * @param f   A transformation
843      * @param <U> Type of transformation result
844      * @return An instance of type {@code U}
845      * @throws NullPointerException if {@code f} is null
846      */
847     public <U> U transform(Function<? super HashSet<T>, ? extends U> f) {
848         Objects.requireNonNull(f, "f is null");
849         return f.apply(this);
850     }
851 
852     @Override
853     public java.util.HashSet<T> toJavaSet() {
854         return toJavaSet(java.util.HashSet::new);
855     }
856 
857     @SuppressWarnings("unchecked")
858     @Override
859     public HashSet<T> union(Set<? extends T> elements) {
860         Objects.requireNonNull(elements, "elements is null");
861         if (isEmpty()) {
862             if (elements instanceof HashSet) {
863                 return (HashSet<T>) elements;
864             } else {
865                 return HashSet.ofAll(elements);
866             }
867         } else if (elements.isEmpty()) {
868             return this;
869         } else {
870             final HashArrayMappedTrie<T, T> that = addAll(tree, elements);
871             if (that.size() == tree.size()) {
872                 return this;
873             } else {
874                 return new HashSet<>(that);
875             }
876         }
877     }
878 
879     @Override
880     public <T1, T2> Tuple2<HashSet<T1>, HashSet<T2>> unzip(
881             Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
882         Objects.requireNonNull(unzipper, "unzipper is null");
883         final Tuple2<Iterator<T1>, Iterator<T2>> t = iterator().unzip(unzipper);
884         return Tuple.of(HashSet.ofAll(t._1), HashSet.ofAll(t._2));
885     }
886 
887     @Override
888     public <T1, T2, T3> Tuple3<HashSet<T1>, HashSet<T2>, HashSet<T3>> unzip3(
889             Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
890         Objects.requireNonNull(unzipper, "unzipper is null");
891         final Tuple3<Iterator<T1>, Iterator<T2>, Iterator<T3>> t = iterator().unzip3(unzipper);
892         return Tuple.of(HashSet.ofAll(t._1), HashSet.ofAll(t._2), HashSet.ofAll(t._3));
893     }
894 
895     @Override
896     public <U> HashSet<Tuple2<T, U>> zip(Iterable<? extends U> that) {
897         return zipWith(that, Tuple::of);
898     }
899 
900     @Override
901     public <U, R> HashSet<R> zipWith(Iterable<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper) {
902         Objects.requireNonNull(that, "that is null");
903         Objects.requireNonNull(mapper, "mapper is null");
904         return HashSet.ofAll(iterator().zipWith(that, mapper));
905     }
906 
907     @Override
908     public <U> HashSet<Tuple2<T, U>> zipAll(Iterable<? extends U> that, T thisElem, U thatElem) {
909         Objects.requireNonNull(that, "that is null");
910         return HashSet.ofAll(iterator().zipAll(that, thisElem, thatElem));
911     }
912 
913     @Override
914     public HashSet<Tuple2<T, Integer>> zipWithIndex() {
915         return zipWithIndex(Tuple::of);
916     }
917 
918     @Override
919     public <U> HashSet<U> zipWithIndex(BiFunction<? super T, ? super Integer, ? extends U> mapper) {
920         Objects.requireNonNull(mapper, "mapper is null");
921         return HashSet.ofAll(iterator().zipWithIndex(mapper));
922     }
923 
924     // -- Object
925 
926     @Override
927     public boolean equals(Object o) {
928         return Collections.equals(this, o);
929     }
930 
931     @Override
932     public int hashCode() {
933         return Collections.hashUnordered(this);
934     }
935 
936     @Override
937     public String stringPrefix() {
938         return "HashSet";
939     }
940 
941     @Override
942     public String toString() {
943         return mkString(stringPrefix() + "(", ", ", ")");
944     }
945 
946     private static <T> HashArrayMappedTrie<T, T> addAll(HashArrayMappedTrie<T, T> initial,
947             Iterable<? extends T> additional) {
948         HashArrayMappedTrie<T, T> that = initial;
949         for (T t : additional) {
950             that = that.put(t, t);
951         }
952         return that;
953     }
954 
955     // -- Serialization
956 
957     /**
958      * {@code writeReplace} method for the serialization proxy pattern.
959      * <p>
960      * The presence of this method causes the serialization system to emit a SerializationProxy instance instead of
961      * an instance of the enclosing class.
962      *
963      * @return A SerializationProxy for this enclosing class.
964      */
965     @GwtIncompatible("The Java serialization protocol is explicitly not supported")
966     private Object writeReplace() {
967         return new SerializationProxy<>(this.tree);
968     }
969 
970     /**
971      * {@code readObject} method for the serialization proxy pattern.
972      * <p>
973      * Guarantees that the serialization system will never generate a serialized instance of the enclosing class.
974      *
975      * @param stream An object serialization stream.
976      * @throws java.io.InvalidObjectException This method will throw with the message "Proxy required".
977      */
978     @GwtIncompatible("The Java serialization protocol is explicitly not supported")
979     private void readObject(ObjectInputStream stream) throws InvalidObjectException {
980         throw new InvalidObjectException("Proxy required");
981     }
982 
983     /**
984      * A serialization proxy which, in this context, is used to deserialize immutable, linked Lists with final
985      * instance fields.
986      *
987      * @param <T> The component type of the underlying list.
988      */
989     // DEV NOTE: The serialization proxy pattern is not compatible with non-final, i.e. extendable,
990     // classes. Also, it may not be compatible with circular object graphs.
991     @GwtIncompatible("The Java serialization protocol is explicitly not supported")
992     private static final class SerializationProxy<T> implements Serializable {
993 
994         private static final long serialVersionUID = 1L;
995 
996         // the instance to be serialized/deserialized
997         private transient HashArrayMappedTrie<T, T> tree;
998 
999         /**
1000          * Constructor for the case of serialization, called by {@link HashSet#writeReplace()}.
1001          * <p/>
1002          * The constructor of a SerializationProxy takes an argument that concisely represents the logical state of
1003          * an instance of the enclosing class.
1004          *
1005          * @param tree a Cons
1006          */
1007         SerializationProxy(HashArrayMappedTrie<T, T> tree) {
1008             this.tree = tree;
1009         }
1010 
1011         /**
1012          * Write an object to a serialization stream.
1013          *
1014          * @param s An object serialization stream.
1015          * @throws java.io.IOException If an error occurs writing to the stream.
1016          */
1017         private void writeObject(ObjectOutputStream s) throws IOException {
1018             s.defaultWriteObject();
1019             s.writeInt(tree.size());
1020             for (Tuple2<T, T> e : tree) {
1021                 s.writeObject(e._1);
1022             }
1023         }
1024 
1025         /**
1026          * Read an object from a deserialization stream.
1027          *
1028          * @param s An object deserialization stream.
1029          * @throws ClassNotFoundException If the object's class read from the stream cannot be found.
1030          * @throws InvalidObjectException If the stream contains no list elements.
1031          * @throws IOException            If an error occurs reading from the stream.
1032          */
1033         private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
1034             s.defaultReadObject();
1035             final int size = s.readInt();
1036             if (size < 0) {
1037                 throw new InvalidObjectException("No elements");
1038             }
1039             HashArrayMappedTrie<T, T> temp = HashArrayMappedTrie.empty();
1040             for (int i = 0; i < size; i++) {
1041                 @SuppressWarnings("unchecked")
1042                 final T element = (T) s.readObject();
1043                 temp = temp.put(element, element);
1044             }
1045             tree = temp;
1046         }
1047 
1048         /**
1049          * {@code readResolve} method for the serialization proxy pattern.
1050          * <p>
1051          * Returns a logically equivalent instance of the enclosing class. The presence of this method causes the
1052          * serialization system to translate the serialization proxy back into an instance of the enclosing class
1053          * upon deserialization.
1054          *
1055          * @return A deserialized instance of the enclosing class.
1056          */
1057         private Object readResolve() {
1058             return tree.isEmpty() ? HashSet.empty() : new HashSet<>(tree);
1059         }
1060     }
1061 }